/*
 *    Copyright (C) 2011-2012 Hai Bison
 *
 *    See the file LICENSE at the root directory of this project for copying
 *    permission.
 */

/*
 * PanelPreferencesEmailAccounts.java
 *
 * Created on Sep 10, 2011, 6:41:58 PM
 */
package group.pals.mailgate.preferences.ui;

import group.pals.mailgate.EmailAccountTester;
import group.pals.mailgate.beans.ItemEmailAccount;
import group.pals.mailgate.beans.ItemEmailProvider;
import group.pals.mailgate.beans.Utils;
import group.pals.mailgate.ui.IPreferences;
import group.pals.mailgate.ui.RightAlignCellRenderer;
import group.pals.mailgate.preferences.Preferences;
import group.pals.utils.sys.MessageBox;
import group.pals.utils.ui.JEditorPopupMenu;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;

/**
 *
 * @author Hai Bison
 */
public class PanelPreferencesEmailAccounts extends javax.swing.JPanel implements IPreferences {

    private final Utils BeansUtils;
    private final group.pals.mailgate.ui.Utils UIUtils;
    private final Preferences _Preferences;
    private final DefaultTableModel TableModel;
    private final Map<String, Integer> MapCols;

    /** Creates new form PanelPreferencesEmailAccounts */
    public PanelPreferencesEmailAccounts() {
        initComponents();

        this.BeansUtils = Utils.getInstance();
        this.UIUtils = group.pals.mailgate.ui.Utils.getInstance();
        this._Preferences = Preferences.getInstance();

        initActions();
        initListeners();
        initTable();

        this.TableModel = (DefaultTableModel) tableEmailAccounts.getModel();
        this.MapCols = new HashMap<String, Integer>();
        for (String header : TableHeaders) {
            this.MapCols.put(header, tableEmailAccounts.getColumn(header).getModelIndex());
        }

        initUI();
    }

    private void initActions() {
        actionAddNewEmailAccount = new ActionAddNewEmailAccount();
        actionRemoveEmailAccount = new ActionRemoveEmailAccount();
        actionClearAllEmailAccounts = new ActionClearAllEmailAccounts();
        actionSaveEmailAccount = new ActionSaveEmailAccount();

        btnAddNewMailAccount.setAction(actionAddNewEmailAccount);
        btnRemoveMailAccount.setAction(actionRemoveEmailAccount);
        btnClearAllMailAccounts.setAction(actionClearAllEmailAccounts);
        btnSave.setAction(actionSaveEmailAccount);
    }

    private void initListeners() {
        Component[] components = {txtEmailAddress, txtEmailPassword};

        DocumentListener documentListener = new DocumentListener() {

            public void insertUpdate(DocumentEvent e) {
                doHandle();
            }

            public void removeUpdate(DocumentEvent e) {
                doHandle();
            }

            public void changedUpdate(DocumentEvent e) {
                doHandle();
            }

            private void doHandle() {
                actionSaveEmailAccount.setEnabled(true);
            }
        };

        for (Component comp : components) {
            if (comp instanceof JTextComponent) {
                ((JTextComponent) comp).getDocument().addDocumentListener(documentListener);
            }
        }

        KeyAdapter keyAdapter = new KeyAdapter() {

            @Override
            public void keyReleased(KeyEvent e) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_ENTER: {
                        if (actionSaveEmailAccount.isEnabled()) {
                            actionSaveEmailAccount.actionPerformed(new ActionEvent(e.getSource(), ActionEvent.ACTION_PERFORMED, ""));
                        }
                    }//VK_ENTER

                    case KeyEvent.VK_ESCAPE: {
                        loadDetailsEmailAccount(getSelectedEmailAccount());
                    }//VK_ESCAPE
                }
            }
        };

        for (Component comp : components) {
            comp.addKeyListener(keyAdapter);
        }
    }
    /*----------------------------------------------------------------------------
     * Table Data
     */
    private final String ColRowNo = "#";
    private final String ColEmail = "E-mail";
    private final String ColProvider = "Provider";
    private final String[] TableHeaders = {ColRowNo, ColEmail, ColProvider};
    private final Class[] TableHeaderClasses = {String.class, ItemEmailAccount.class,
        ItemEmailProvider.class};

    //<editor-fold defaultstate="collapsed" desc="table initialization">
    private void initTable() {
        tableEmailAccounts.setModel(new javax.swing.table.DefaultTableModel(
                new Object[][]{}, TableHeaders) {

            @Override
            public Class getColumnClass(int columnIndex) {
                return TableHeaderClasses[columnIndex];
            }

            @Override
            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return false;
            }

            @Override
            public Object getValueAt(int row, int column) {
                final String ColName = getColumnName(column);

                if (ColName.equals(ColRowNo)) {
                    return String.format("%,02d", row + 1);
                } else if (ColName.equals(ColEmail)) {
                    return super.getValueAt(row, column);
                } else {
                    ItemEmailAccount ep = (ItemEmailAccount) super.getValueAt(row, MapCols.get(ColEmail));

                    if (ColName.equals(ColProvider)) {
                        return BeansUtils.getEmailProvider(ep);
                    }

                    return super.getValueAt(row, column);
                }
            }//getValueAt()
        });

        //------------------------ Init columns
        RightAlignCellRenderer rightAlignCellRenderer = new RightAlignCellRenderer();
        rightAlignCellRenderer.setCellHorzAlignment(SwingConstants.RIGHT);

        TableColumn col = tableEmailAccounts.getColumn(ColRowNo);
        col.setCellRenderer(rightAlignCellRenderer);
        col.setMinWidth(50);
        col.setMaxWidth(50);

        //-------------------------- Listeners
        tableEmailAccounts.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    loadDetailsEmailAccount(getSelectedEmailAccount());
                }
            }
        });

        tableEmailAccounts.getModel().addTableModelListener(new TableModelListener() {

            public void tableChanged(TableModelEvent e) {
                loadDetailsEmailAccount(e.getType() == TableModelEvent.DELETE ? null : getSelectedEmailAccount());
            }
        });
    }// </editor-fold>

    private void initUI() {
        JEditorPopupMenu editorPopupMenu = UIUtils.getEditorPopupMenu();
        txtEmailAddress.setComponentPopupMenu(editorPopupMenu);
        txtEmailPassword.setComponentPopupMenu(editorPopupMenu);
    }

    private void loadDetailsEmailAccount(ItemEmailAccount emailAccount) {
        txtEmailAddress.setText(emailAccount == null ? null : emailAccount.getEmailAddress());
        txtEmailPassword.setText(emailAccount == null ? null : emailAccount.getPassword());

        group.pals.utils.ui.Utils.enableContainer(panelDetails, emailAccount != null);
        actionSaveEmailAccount.setEnabled(emailAccount != null);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        toolBarMailAccounts = new javax.swing.JToolBar();
        btnAddNewMailAccount = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JToolBar.Separator();
        btnRemoveMailAccount = new javax.swing.JButton();
        jSeparator2 = new javax.swing.JToolBar.Separator();
        btnClearAllMailAccounts = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        tableEmailAccounts = new javax.swing.JTable();
        panelDetails = new javax.swing.JPanel();
        txtEmailAddress = new javax.swing.JTextField();
        txtEmailPassword = new javax.swing.JPasswordField();
        btnSave = new javax.swing.JButton();

        setLayout(new java.awt.GridBagLayout());

        toolBarMailAccounts.setFloatable(false);
        toolBarMailAccounts.setRollover(true);

        btnAddNewMailAccount.setText("jButton1");
        btnAddNewMailAccount.setFocusable(false);
        btnAddNewMailAccount.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnAddNewMailAccount.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        toolBarMailAccounts.add(btnAddNewMailAccount);
        toolBarMailAccounts.add(jSeparator1);

        btnRemoveMailAccount.setText("jButton2");
        btnRemoveMailAccount.setFocusable(false);
        btnRemoveMailAccount.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnRemoveMailAccount.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        toolBarMailAccounts.add(btnRemoveMailAccount);
        toolBarMailAccounts.add(jSeparator2);

        btnClearAllMailAccounts.setText("jButton3");
        btnClearAllMailAccounts.setFocusable(false);
        btnClearAllMailAccounts.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnClearAllMailAccounts.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        toolBarMailAccounts.add(btnClearAllMailAccounts);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        add(toolBarMailAccounts, gridBagConstraints);

        tableEmailAccounts.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        tableEmailAccounts.getTableHeader().setReorderingAllowed(false);
        jScrollPane2.setViewportView(tableEmailAccounts);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weighty = 1.0;
        add(jScrollPane2, gridBagConstraints);

        panelDetails.setBorder(javax.swing.BorderFactory.createTitledBorder("Details:"));
        panelDetails.setLayout(new java.awt.GridBagLayout());

        txtEmailAddress.setBorder(javax.swing.BorderFactory.createTitledBorder("E-mail address:"));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        gridBagConstraints.weightx = 1.0;
        panelDetails.add(txtEmailAddress, gridBagConstraints);

        txtEmailPassword.setBorder(javax.swing.BorderFactory.createTitledBorder("Password:"));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        panelDetails.add(txtEmailPassword, gridBagConstraints);

        btnSave.setText("jButton1");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTHEAST;
        panelDetails.add(btnSave, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        add(panelDetails, gridBagConstraints);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnAddNewMailAccount;
    private javax.swing.JButton btnClearAllMailAccounts;
    private javax.swing.JButton btnRemoveMailAccount;
    private javax.swing.JButton btnSave;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JToolBar.Separator jSeparator1;
    private javax.swing.JToolBar.Separator jSeparator2;
    private javax.swing.JPanel panelDetails;
    private javax.swing.JTable tableEmailAccounts;
    private javax.swing.JToolBar toolBarMailAccounts;
    private javax.swing.JTextField txtEmailAddress;
    private javax.swing.JPasswordField txtEmailPassword;
    // End of variables declaration//GEN-END:variables

    /*----------------------------------------------------------------------------
     * IPreferences
     */
    public void loadPreferences() {
        TableModel.setRowCount(0);

        List<ItemEmailAccount> emailProviders = _Preferences.getEmailAccounts();
        Object[] row = new Object[TableHeaders.length];
        for (ItemEmailAccount ea : emailProviders) {
            row[MapCols.get(ColEmail)] = ea;
            TableModel.addRow(row);
        }
        TableModel.fireTableDataChanged();

        group.pals.utils.ui.Utils.enableContainer(panelDetails, false);
    }

    public boolean storePreferences(boolean prepare) {
        List<ItemEmailAccount> emailAccounts = new ArrayList<ItemEmailAccount>();
        for (int r = 0; r < TableModel.getRowCount(); r++) {
            emailAccounts.add((ItemEmailAccount) TableModel.getValueAt(r, MapCols.get(ColEmail)));
        }
        _Preferences.setEmailAccounts(emailAccounts);

        return true;
    }

    public void closeResources() {
        //do nothing
    }

    public ItemEmailAccount getSelectedEmailAccount() {
        if (tableEmailAccounts.getSelectedRow() < 0) {
            return null;
        }
        return (ItemEmailAccount) tableEmailAccounts.getValueAt(
                tableEmailAccounts.getSelectedRow(), MapCols.get(ColEmail));
    }

    /*----------------------------------------------------------------------------
     * ACTIONS
     */

    /*----------------------------------------------------------------------------
     * ActionAddNewEmailAccount
     */
    private ActionAddNewEmailAccount actionAddNewEmailAccount;

    private class ActionAddNewEmailAccount extends AbstractAction {

        public ActionAddNewEmailAccount() {
            super("Add New...");
        }

        public void actionPerformed(ActionEvent e) {
            Object[] row = new Object[TableHeaders.length];
            row[MapCols.get(ColEmail)] = new ItemEmailAccount("Unknown", "");
            TableModel.addRow(row);
            int r = tableEmailAccounts.getRowCount() - 1;
            tableEmailAccounts.setRowSelectionInterval(r, r);
            txtEmailAddress.requestFocusInWindow();
            txtEmailAddress.selectAll();
        }
    }

    /*----------------------------------------------------------------------------
     * ActionRemoveEmailAccount
     */
    private ActionRemoveEmailAccount actionRemoveEmailAccount;

    private class ActionRemoveEmailAccount extends AbstractAction {

        public ActionRemoveEmailAccount() {
            super("Remove");
        }

        public void actionPerformed(ActionEvent e) {
            if (tableEmailAccounts.getSelectedRowCount() > 0
                    && MessageBox.confirmYesNo(null, null,
                    "Are you sure you want to remove selected account(s)?", 1)) {
                for (int r = tableEmailAccounts.getRowCount(); r >= 0; r--) {
                    if (tableEmailAccounts.isRowSelected(r)) {
                        TableModel.removeRow(tableEmailAccounts.convertRowIndexToModel(r));
                    }
                }
                TableModel.fireTableDataChanged();
            }
        }
    }
    /*----------------------------------------------------------------------------
     * ActionClearAllEmailAccounts
     */
    private ActionClearAllEmailAccounts actionClearAllEmailAccounts;

    private class ActionClearAllEmailAccounts extends AbstractAction {

        public ActionClearAllEmailAccounts() {
            super("Clear All");
        }

        public void actionPerformed(ActionEvent e) {
            if (TableModel.getRowCount() > 0
                    && MessageBox.confirmYesNo(null, null, "Are you sure you want to clear all accounts?", 1)) {
                TableModel.setRowCount(0);
            }
        }
    }
    /*----------------------------------------------------------------------------
     * ActionSaveEmailProvider
     */
    private ActionSaveEmailAccount actionSaveEmailAccount;

    private class ActionSaveEmailAccount extends AbstractAction {

        public ActionSaveEmailAccount() {
            super("Save");
            putValue(ACCELERATOR_KEY,
                    KeyStroke.getKeyStroke('S', InputEvent.CTRL_DOWN_MASK));
        }

        public void actionPerformed(ActionEvent e) {
            if (tableEmailAccounts.getSelectedRowCount() != 1) {
                return;
            }

            String emailAddress = txtEmailAddress.getText().trim();
            String emailPassword = new String(txtEmailPassword.getPassword());
            if (emailAddress.isEmpty() || emailPassword.isEmpty()) {
                MessageBox.showErrMsg(null, null, "E-mail address or password can not be empty");
                return;
            }

            ItemEmailAccount emailAccount = getSelectedEmailAccount();
            emailAccount.setEmailAddress(emailAddress);
            emailAccount.setPassword(emailPassword);

            testEmailAccount(emailAccount);

            setEnabled(false);
            TableModel.fireTableDataChanged();

            //restore last selected row
            final int Col = MapCols.get(ColEmail);
            for (int row = 0; row < tableEmailAccounts.getRowCount(); row++) {
                if (tableEmailAccounts.getValueAt(row, Col).equals(emailAccount)) {
                    tableEmailAccounts.getSelectionModel().setSelectionInterval(row, row);
                    break;
                }
            }
        }

        private void testEmailAccount(ItemEmailAccount emailAccount) {
            ItemEmailProvider emailProvider = Utils.getInstance().getEmailProvider(emailAccount);
            if (emailProvider == null) {
                MessageBox.showWarningMsg(null, null,
                        String.format("Could not find e-mail provider for \"%s\"", emailAccount));
                return;
            }

            new EmailAccountTester(emailAccount, emailProvider).test();
//      DialogEmailAccountTester.test(emailAccount, emailProvider, null);
        }
    }
}
